package cn.topcodes.tcsf.admin.commons.api.controller.query;

import cn.topcode.unicorn.utils.I18nUtil;
import cn.topcodes.tcsf.admin.commons.api.convertor.HttpEntity2VoConvertor;
import cn.topcodes.tcsf.admin.commons.api.domain.ApiResponseEntity;
import cn.topcodes.tcsf.admin.commons.domain.Page;
import cn.topcodes.tcsf.admin.commons.query.IQueryService;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public abstract class QueryApiController<T,V> implements QueryApi<V> {
	
	@Autowired
	private IQueryService<T> queryService;

	@Autowired(required = false)
	private HttpEntity2VoConvertor<T,V> entity2VoConvertor;

	@Override
	public ApiResponseEntity<V> get(HttpServletRequest request, @ApiParam(value="资源ID") @RequestParam(required=true) Long id) {
		T t = this.queryService.findOne(id);
		ApiResponseEntity<V> apiResponse = null;
		if(t == null) {
			apiResponse = ApiResponseEntity.buildNotFound();
		}else {
			V v = this.entity2Vo(t,request);
			apiResponse = ApiResponseEntity.buildOK();
			apiResponse.setBody(v);
		}
		return apiResponse;
	}
	
	@Override
	public ApiResponseEntity<List<V>> list(
			HttpServletRequest request
	) {
		Map<String,String[]> searchParams = request.getParameterMap();
		List<T> listT = this.queryService.findAll(searchParams);
		List<V> listV = this.entity2Vo(listT,request);
		ApiResponseEntity<List<V>> apiResponse = ApiResponseEntity.buildOK();
		return apiResponse.setBody(listV);
	}
	
	@Override
	public ApiResponseEntity<Page<V>> pageList(
			HttpServletRequest request,
			@ApiParam(value="页号") @RequestParam(value="page",required=false,defaultValue="1") Integer pageNumber,
			@ApiParam(value="每页条数") @RequestParam(value="size",required=false,defaultValue="10") Integer pageSize
			) {
		Map<String,String[]> searchParams = request.getParameterMap();
		Page<T> pageT = this.queryService.findPage(searchParams, pageNumber, pageSize);
		Page<V> pageV = this.entity2Vo(pageT,request);
		ApiResponseEntity<Page<V>> apiResponse = ApiResponseEntity.buildOK();
		return apiResponse.setBody(pageV);
	}

	protected Page<V> entity2Vo(Page<T> pageEntity,HttpServletRequest request) {
		Assert.notNull(pageEntity);
		if(this.entity2VoConvertor != null) {
			return this.entity2VoConvertor.convertPage(pageEntity,request);
		}else {
			List<V> vos = entity2Vo(pageEntity.getRows(),request);
			return new Page<V>(vos,pageEntity.getTotal(),pageEntity.getPageNumber(),pageEntity.getPageSize());
		}
	}

	protected List<V> entity2Vo(List<T> entitys,HttpServletRequest request) {
		Assert.notNull(entitys);
		if(this.entity2VoConvertor != null) {
			return this.entity2VoConvertor.convertList(entitys,request);
		}else {
			List<V> vos = new ArrayList<V>();
			for(T entity : entitys) {
				vos.add(entity2Vo(entity,request));
			}
			return vos;
		}
	}

	protected V entity2Vo(T entity, HttpServletRequest request) {
		Assert.notNull(entity);
		Class<V> voClass = this.getVoClass();
		if(this.queryService.getEntityClass().equals(voClass)) {
			I18nUtil.processAnnotation(request,entity);
			return (V) entity;
		}
		if(this.entity2VoConvertor != null) {
			return this.entity2VoConvertor.convert(entity,request);
		}else {
			try {
				V vo = this.getVoClass().newInstance();
				BeanUtils.copyProperties(entity, vo);
				entity2VoDiff(entity, vo);
				I18nUtil.processAnnotation(request,vo);
				return vo;
			} catch (Exception e) {
				throw new IllegalStateException("实体类型定义有误", e);
			}
		}
	}

	@Override
	public ApiResponseEntity exist(HttpServletRequest request, Long id, String property, String value) {
		boolean exist = this.queryService.exist(id,property,value);
		return ApiResponseEntity.buildOK().setBody(exist);
	}

	protected void entity2VoDiff(T entity, V vo) {

	}

	@SuppressWarnings("unchecked")
	public Class<V> getVoClass() {
		Class<V> voClass = (Class<V>) ((ParameterizedType) getClass().getGenericSuperclass())
				.getActualTypeArguments()[1];
		return voClass;
	}

}
